var logger = require("../utils/log");

var socketMgr = require("./socket_service");
var roomMgr = require("./roommgr");
var redis = require("../utils/redis");

var games = {};
var gamesSeats = {};

const PERIOD_IDLE_0 = 0; //空闲状态
const PERIOD_TOREADY_1 = 1; //准备(算完积分就可以准备，房主开始游戏跳过此阶段)
const PERIOD_TOZHUANG_3 = 3; //抢庄
const PERIOD_XIAZHU_5 = 5; //下注阶段
const PERIOD_TOOPEN_7 = 7; //开牌(通知开牌)
const PERIOD_END_9 = -1; //结束(算完积分就可以游戏可能结束)
const PERIOD_DISSOLVE_99 = 99; //正在解散

// const PERIOD_NOTIFY_HOLD_2 = 2; //发手牌
// const PERIOD_NOTIFY_ZHUANG_4 = 4; //通知庄
// const PERIOD_NOTIFY_HOLDMORE_6 = 6; //补手牌
// const PERIOD_SCORE_8 = 8; //积分

var times = {};

//初始化数据
function setupGame(room) {
    //牌局共享的数据 包括状态 顺序 出牌
    var game = {
        room:room,
        numOfGames:-1,
        type:room.conf.type,
        roomNo:room.roomNo,
    };
    game.plays = room.players.length;//玩家数量 默认是4 也可以是3
    game.gameSeats = new Array(game.plays);//座位信息

    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i] = {};

        seat.game = game;
        seat.seatIndex = i;//0 1 2 3
        seat.userId = room.players[i].userId;

        gamesSeats[seat.userId] = seat;
    }

    games[room.roomNo] = game;
    refreshGame(game);

    return game;
};

function refreshGame(game) {
    game.memberOfReady = 0;//准备的人数
    game.memberOfToZhuang = 0;//抢庄的人数
    game.memberOfXiazhu = 0;//下注的人数
    game.memberOfOpen = 0;//开牌的人数
    game.memberOfAgree = 0;//同意的人数
    game.memberOfRefuse = 0;//拒绝的人数
    game.paiLength = 52;//牌的长度 蚌埠麻将200张字
    game.pkPais = null;//麻将牌
    game.state = -1;//0准备下一局  999正在请求解散
    game.turn = 0;//当前轮到谁
    game.index = 0;//牌的下标
    game.zhuang = null;
    game.zhuangBei = 0;

    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];

        seat.ready = false;
        //-1 表示没执行抢庄动作
        seat.toZhuang = -1;
        //-1 表示没执行下注动作
        seat.xiaZhu = -1;
        //是否开牌
        seat.niuX = -1;
        //持有的牌
        seat.holds = [];
        //补的牌
        seat.holdsMore = null;
    }
    game.numOfGames++;
};

function xiPai() {
    var pkPais = new Array(games.paiLength);

    //40-52黑桃 27-39红桃 14-26梅花 1-13方块
    var index = 0;
    for (var i = 1; i < 53; i++) {
        pkPais[index] = i;
        index++;
    }

    //乱序
    for (var i = 0; i < 52; i++) {
        var lastIndex = 51-i;
        var index = Math.floor(Math.random() * lastIndex);
        var t = pkPais[index];
        pkPais[index] = pkPais[lastIndex];
        pkPais[lastIndex] = t;
    }

    games.pkPais = pkPais;
};

function faPai(game) {
    var bupai = game.type == 13; //13表示是明牌抢庄
    var length = bupai ? 4*game.plays : 5*game.plays;
    for (var i = 0; i < length; i++) {
        moPai(game);
        moveToNextUser(game);
    }

    //通知手牌
    socketMgr.notify_holds(game);
    //进入到抢庄阶段
    game.state = PERIOD_TOZHUANG_3;

    if (bupai) { //补牌阶段
        for (var j = 0; j < game.plays; j++) {
            moBuPai(game);
            moveToNextUser(game);
        }
    }
};

function moPai(game) {
    if (game.index == game.paiLength) return -1;

    var seat = game.gameSeats[game.turn];
    var pai = game.pkPais[game.index];
    seat.holds.push(pai);
    game.index++;

    return pai;
};

function moBuPai(game) {
    if (game.index == game.paiLength) return -1;

    var seat = game.gameSeats[game.turn];
    var pai = game.pkPais[game.index];
    seat.holdsMore = pai;
    game.index++;

    return pai;
};

function moveToNextUser(game){
    game.turn++;
    game.turn %= game.plays;
    return game.gameSeats[game.turn];
};

//开始游戏
function beginGame(userId, roomNo) {
    if (!roomMgr.isCreator(roomNo, userId)) return;
    var room = roomMgr.getRoomByRoomNo(roomNo);
    if(room == null) {
        logger.error("begin error", roomNo);
        return;
    }
    var game = setupGame(room);
    game.state = PERIOD_TOREADY_1;
    xiPai(game);
    faPai(game);
};

//准备
function ready(userId) {
    var seat = gamesSeats[userId];
    var game = seat.game;
    if (!seat.ready) {
        game.memberOfReady++;
        seat.ready = true;
    }

    if (seat.memberOfReady == game.gameSeats.length) {
        //清除定时器
        var timeout = times[game.roomNo];
        if (timeout) {
            clearTimeout(timeout);
            times[game.roomNo] = null;
        }
        nextGame(game);
        return;
    }
    if (times[game.roomNo] == null) {
        var timeout = setTimeout(function () {
            times[game.roomNo] = null;
            nextGame(game);
        }, 15000);//15s后
        times[game.roomNo] = timeout;
    }
    return seat.ready;
};

//下一局游戏 倒计时结束 进入到发牌阶段
function nextGame(game) {
    refreshGame(game);
    xiPai(game);
    faPai(game);
};

//抢庄
function toZhuang(userId, zhuangBei) {
    var seat = gamesSeats[userId];
    var game = seat.game;
    if (seat.toZhuang < 0) {
        game.memberOfToZhuang++;
        seat.toZhuang = zhuangBei;
        if (game.zhuangBei < zhuangBei) {
            game.zhuangBei = zhuangBei;
        }
    }

    if (seat.memberOfZhuang == game.gameSeats.length) {
        //清除定时器
        var timeout = times[game.roomNo];
        if (timeout) {
            clearTimeout(timeout);
            times[game.roomNo] = null;
        }
        calcZhuang(game);
        return;
    }
    if (times[game.roomNo] == null) {
        var timeout = setTimeout(function () {
            times[game.roomNo] = null;
            calcZhuang(game);
        }, 15000);//15s后
        times[game.roomNo] = timeout;
    }
    return seat.toZhuang;
};

//计算庄家
function calcZhuang(game) {
    var zhuangs = [];
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        if (seat.toZhuang >= game.zhuangBei) {
            zhuangs.push(seat.userId);
        }
    }

    //没人抢庄
    if (game.zhuangBei == 0) {
        game.zhuangBei = 1;
    }

    var index = randomIndex(zhuangs.length);
    game.zhuang = zhuangs[index];

    //通知庄家
    socketMgr.notify_zhuang(game);
    //进入下注阶段
    game.state = PERIOD_XIAZHU_5;
};

//下注
function xiaZhu(userId, zhu) {
    var seat = gamesSeats[userId];
    var game = seat.game;
    if (seat.xiaZhu < 0) {
        game.memberOfXiazhu++;
        seat.xiaZhu = zhu;
    }

    if (seat.memberOfZhu == game.gameSeats.length) {
        //清除定时器
        var timeout = times[game.roomNo];
        if (timeout) {
            clearTimeout(timeout);
            times[game.roomNo] = null;
        }
        buPai(game);
        return;
    }
    if (times[game.roomNo] == null) {
        var timeout = setTimeout(function () {
            times[game.roomNo] = null;
            setDefaultZhu(game);
            buPai(game);
        }, 15000);//15s后
        times[game.roomNo] = timeout;
    }
    return seat.xiaZhu;
};

//设置默认注
function setDefaultZhu(game) {
    //有人没抢庄设置成抢庄0倍
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        if (seat.xiaZhu < 0) {
            seat.xiaZhu = 2;//默认下注倍数
        }
    }
};

//补牌
function buPai(game) {
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        seat.holds.push(seat.holdsMore);
    }
    //通知补牌
    socketMgr.notify_holds_more(game);
    //进入到开牌阶段
    game.state = PERIOD_TOOPEN_7;
};

//开牌
function openPai(userId) {
    var seat = gamesSeats[userId];
    var game = seat.game;

    if (seat.niuX < 0) {
        game.memberOfOpen++;
        seat.holds.sort(function (a, b) {
            return b - a; //从大到小
        });
        seat.niuX = suanNiu(seat.holds);
        //通知牛几
        socketMgr.notify_niu(seat);
    }

    if (seat.memberOfZhu == game.gameSeats.length) {
        //清除定时器
        var timeout = times[game.roomNo];
        if (timeout) {
            clearTimeout(timeout);
            times[game.roomNo] = null;
        }
        calcScore(game);
        return;
    }
    if (times[game.roomNo] == null) {
        var timeout = setTimeout(function () {
            times[game.roomNo] = null;
            autoOpenPai(game);
            calcScore(game);
        }, 15000);//15s后
        times[game.roomNo] = timeout;
    }
    return seat.niuX;
};

//自动开牌
function autoOpenPai(game) {
    //有人没亮牌
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        if (seat.niuX < 0) {
            seat.holds.sort(function (a, b) {
                return b - a; //从大到小
            });
            seat.niuX = suanNiu(seat.holds);
            //通知牛几
            socketMgr.notify_niu(seat);
        }
    }
};

//算积分
function calcScore(game) {
    var seats = new Array(game.plays); //去排序新数组 不影响原来的数组
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        seats[i] = seat;
    }

    seats.sort(function (sa, sb) {
        if (sb.niuX == sa.niuX) { //牛同样的牛
            return sb.holds[0] - sa.holds[0];//从大到小
        } else {
            return sb.niuX - sa.niuX;//从大到小
        }
    });

    var zhuangSeat = null;
    var zhuangScore = 0;
    var zhuangWinIndex = -1;

    var isPlus = true;
    var gameScore = {};

    for (var i = 0; i < game.plays; i++) {
        var seat = seats[i];
        if (seat.userId === game.zhuang) { //庄的位置
            zhuangSeat = seat;
            zhuangWinIndex = i;

            isPlus = false;
            continue;
        }
        var score = suanBeishu(seat.niuX)*game.zhuangBei*seat.xiaZhu;
        if (isPlus) { //庄输
            zhuangScore -= score;
            gameScore[seat.userId] = score;
        } else { //庄赢
            zhuangScore += score;
            gameScore[seat.userId] = -score;
        }
    }

    gameScore[game.zhuang] = zhuangScore;
    game.room.results.push(gameScore);

    //缓存每一局游戏的数据
    var key = redis.redisCacheKey(redis.REDIS_ROOM_RESULT_INFO, game.room.roomNo);
    redis.redisClient.sadd(key, JSON.stringify(gameScore));

    game.room.results.push(gameScore);
    var statistics = game.room.statistics;
    for (var userId in gameScore) {
        var score = statistics[userId];
        if (score) {
            score += gameScore[userId];
        }
        statistics[userId] = score;
    }

    //通知积分
    socketMgr.notify_score(game);

    if (game.numOfGames == game.room.conf.numOfGames) {
        setTimeout(function () {
            game.state = PERIOD_IDLE_0;
            endGame(game);
        }, 3000);
    } else {
        setTimeout(function () {
            game.state = PERIOD_IDLE_0;
            socketMgr.notify_game_ready(game);
        }, 3000);
    }
};

//结束游戏
function endGame(game, force){
    if (!force) { //强制解散已经通知解散结果
        socketMgr.notify_game_end(game);
    }
    //延迟2S 做断开socket 清理room操作
    setTimeout(function () {
        //关闭房间
        roomMgr.closeRoom(game.room.creator, game.room.roomNo);
        //踢出所有房间socket
        socketMgr.konckout_all(game);
        //清楚房间信息
        delGameInfo(game);
    }, 2000);

};

//清除游戏信息
function delGameInfo(game) {
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        delete gamesSeats[seat.userId];
    }
    delete games[game.roomNo];
    delete times[game.roomNo];
};

//解散请求处理
function dissolveRequest(userId, operate) {
    var seat = gamesSeats[userId];
    var game = seat.game;
    if (operate == 1) { //同意
        game.memberOfAgree++;
    } else {
        game.memberOfRefuse++;
    }
    if (game.memberOfRefuse > 0 || game.memberOfAgree == game.plays) { //超过1人拒绝 或者 所有人都同意
        var timeout = times[game.roomNo];
        if (timeout) {
            clearTimeout(timeout);
            times[game.roomNo] = null;
        }
        if (game.memberOfRefuse > 0) {
            socketMgr.notify_dissolve_result(game, 0);
        } else {
            socketMgr.notify_dissolve_result(game, 1);
            endGame(game, true);
        }
        game.memberOfRefuse = 0;
        game.memberOfAgree = 0;
        return;
    }
    if (times[game.roomNo] == null) {
        var timeout = setTimeout(function () {
            socketMgr.notify_dissolve_result(game, 0);
            times[game.roomNo] = null;
        }, 60000);//60s后
        times[game.roomNo] = timeout;
    }
};

function suanNiu(holds) {
    //临时pai数组
    var paisArr = [];
    //特殊牛
    var paisMap = {};

    var paisMin = 0;
    var paisMax = 0;
    var paisAll = 0;

    //1-13
    //14-26
    //27-39
    //40-52
    for (var k = 0; k < 5; k++) {
        var pai = holds[k];
        //14--25,26
        pai = pai%13;
        if (pai === 0) {
            pai = 13;
        }
        // var huase = Math.round(random/13);
        paisMap.set(pai, 1);

        paisMin += pai;
        if (pai > 10 && pai < 14) {
            paisMax += 11;

            pai = 10;
        }

        paisAll += pai;

        paisArr.push(pai);
    }

    //炸弹牛
    if (paisMap.size === 2) {
        return 13;
    }

    //五小牛
    if (paisMin < 11 && paisMin > 0) {
        return 12;
    }

    //五花牛
    if (paisMax == 55) {
        return 11;
    }

    //箭头函数 以及 高阶函数示例
    // pais = pais.map((x) => { return k>10 && k<14 ? 10 : k });
    // paisArr = paisArr.sort((a, b) => {return a -b});
    // paisArr = paisArr.sort(a - b);

    // paisArr = paisArr.sort(function(a, b) {
    //     return b-a;
    // });

    //牛 递归算牛
    //4 5 6 7 8
    //456 457 458
    //467 468
    var pai1 = 0;
    var pai2 = 0;
    var pai3 = 0;
    var isNiun = false;
    for (var k = 0; k < 3; k++) { //0 1 2
        for (var i = k+1; i < 4; i++) { // 1 2 3
            for (var j = i+1; j < 5; j++) { //2 3 4
                pai1 = paisArr[k];
                pai2 = paisArr[i];
                pai3 = paisArr[j];
                if ((pai1 + pai2 + pai3)%10 === 0) {
                    isNiun = true;
                    break;
                }
            }
            if (isNiun) {
                break;
            }
        }
        if (isNiun) {
            break;
        }
    }

    if (isNiun) {
        var niux = paisAll%10;
        if (niux === 0) {
            niux = 10;
        }
        return niux;
    }
    return 0;
};

function suanBeishu(niuX) {
    var beishu = 1;
    if (niuX < 7) {
        beishu = 1;
    } else if (niuX == 7) {
        beishu = 2;
    } else if (niuX == 8) {
        beishu = 2;
    } else if (niuX == 9) {
        beishu = 3;
    } else if (niuX == 10) {
        beishu = 4;
    } else if (niuX == 11) {
        beishu = 5;
    } else if (niuX == 12) {
        beishu = 6;
    } else if (niuX == 13) {
        beishu = 7;
    }
    return beishu;
};

function randomIndex(num) { //0到x取值
    return Math.floor(Math.random() * num);
};

function gameState(roomNo) {
    var game = games[roomNo];
    if (game == null) return -1;
    return game.state;
};

exports.ready = ready;
exports.beginGame = beginGame;
exports.toZhuang = toZhuang;
exports.xiaZhu = xiaZhu;
exports.openPai = openPai;
exports.endGame = endGame;
exports.dissolveRequest = dissolveRequest;
exports.gameState = gameState;
























